#include "EnterpriseParser.h"

#include "IsoCodeParser.h"
#include "EnterpriseCodeParser.h"
#include "QStringParser.h"

#include <QXmlStreamReader>
#include <QString>

namespace Ipc2581b
{

EnterpriseParser::EnterpriseParser(
    QStringParser *&_idParser
    , QStringParser *&_nameParser
    , QStringParser *&_codeParser
    , EnterpriseCodeParser *&_codeTypeParser
    , QStringParser *&_address1Parser
    , QStringParser *&_address2Parser
    , QStringParser *&_cityParser
    , QStringParser *&_stateProvinceParser
    , IsoCodeParser *&_countryParser
    , QStringParser *&_postalCodeParser
    , QStringParser *&_phoneParser
    , QStringParser *&_faxParser
    , QStringParser *&_emailParser
    , QStringParser *&_urlParser
):    m_idParser(_idParser)
    , m_nameParser(_nameParser)
    , m_codeParser(_codeParser)
    , m_codeTypeParser(_codeTypeParser)
    , m_address1Parser(_address1Parser)
    , m_address2Parser(_address2Parser)
    , m_cityParser(_cityParser)
    , m_stateProvinceParser(_stateProvinceParser)
    , m_countryParser(_countryParser)
    , m_postalCodeParser(_postalCodeParser)
    , m_phoneParser(_phoneParser)
    , m_faxParser(_faxParser)
    , m_emailParser(_emailParser)
    , m_urlParser(_urlParser)
{

}

bool EnterpriseParser::parse(QXmlStreamReader *reader)
{
    /* Pre */

    m_result.reset(new Enterprise());

    /* Attributes */

    QStringRef data;
    if (reader->attributes().hasAttribute(QStringLiteral("id")))
    {
        data = reader->attributes().value(QStringLiteral("id"));
        if (!m_idParser->parse(reader, data))
            return false;
        m_result->id = m_idParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("id: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("name")))
    {
        data = reader->attributes().value(QStringLiteral("name"));
        if (!m_nameParser->parse(reader, data))
            return false;
        m_result->nameOptional = Optional<QString>(m_nameParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("code")))
    {
        data = reader->attributes().value(QStringLiteral("code"));
        if (!m_codeParser->parse(reader, data))
            return false;
        m_result->code = m_codeParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("code: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("codeType")))
    {
        data = reader->attributes().value(QStringLiteral("codeType"));
        if (!m_codeTypeParser->parse(reader, data))
            return false;
        m_result->codeTypeOptional = Optional<EnterpriseCode>(m_codeTypeParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("address1")))
    {
        data = reader->attributes().value(QStringLiteral("address1"));
        if (!m_address1Parser->parse(reader, data))
            return false;
        m_result->address1Optional = Optional<QString>(m_address1Parser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("address2")))
    {
        data = reader->attributes().value(QStringLiteral("address2"));
        if (!m_address2Parser->parse(reader, data))
            return false;
        m_result->address2Optional = Optional<QString>(m_address2Parser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("city")))
    {
        data = reader->attributes().value(QStringLiteral("city"));
        if (!m_cityParser->parse(reader, data))
            return false;
        m_result->cityOptional = Optional<QString>(m_cityParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("stateProvince")))
    {
        data = reader->attributes().value(QStringLiteral("stateProvince"));
        if (!m_stateProvinceParser->parse(reader, data))
            return false;
        m_result->stateProvinceOptional = Optional<QString>(m_stateProvinceParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("country")))
    {
        data = reader->attributes().value(QStringLiteral("country"));
        if (!m_countryParser->parse(reader, data))
            return false;
        m_result->countryOptional = Optional<IsoCode>(m_countryParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("postalCode")))
    {
        data = reader->attributes().value(QStringLiteral("postalCode"));
        if (!m_postalCodeParser->parse(reader, data))
            return false;
        m_result->postalCodeOptional = Optional<QString>(m_postalCodeParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("phone")))
    {
        data = reader->attributes().value(QStringLiteral("phone"));
        if (!m_phoneParser->parse(reader, data))
            return false;
        m_result->phoneOptional = Optional<QString>(m_phoneParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("fax")))
    {
        data = reader->attributes().value(QStringLiteral("fax"));
        if (!m_faxParser->parse(reader, data))
            return false;
        m_result->faxOptional = Optional<QString>(m_faxParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("email")))
    {
        data = reader->attributes().value(QStringLiteral("email"));
        if (!m_emailParser->parse(reader, data))
            return false;
        m_result->emailOptional = Optional<QString>(m_emailParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("url")))
    {
        data = reader->attributes().value(QStringLiteral("url"));
        if (!m_urlParser->parse(reader, data))
            return false;
        m_result->urlOptional = Optional<QString>(m_urlParser->result());
    }

    /* Elements */

    while (reader->readNextStartElement())
    {
        auto name = reader->name();
            reader->skipCurrentElement();
    }

    /* Post */

    // TODO: Check multiplicity of elements/attributes

    return true;
}

Enterprise *EnterpriseParser::result()
{
    return m_result.take();
}

}